

import pandas as pd

# 沿指定轴（行或列）高效拼接多个 DataFrame 或 Series 的核心函数
# 索引不一致，自动外连接对齐（缺失值填 NaN）
# 若需追踪数据来源，用 keys 参数添加多级索引
pd.concat([df1, df2], keys=['Q1', 'Q2'])  # 生成MultiIndex keys=['df1','df2'] 添加前缀

# join='outer'（默认）：取所有列并集，缺失值填充 NaN（适合合并异构数据）
pd.concat([df1, df3], 
        join='inner'  # 只保留共有列（用于提取共同特征）
        ,verify_integrity=True   # 索引重复时报错
        ,sort=False #（默认）避免非连接轴排序，提升速度。
        ,copy=False # 减少数据复制，节省内存（需确保原数据不变) 解决 内存溢出	数据复制过多
        ,ignore_index=True   #  重置索引为连续整数


          )  



# 预先指定数据类型：减少内存占用
result = pd.concat([df_large1, df_large2]).astype({'column': 'int32'})



# -----------------可替代方案
# 简单行堆叠 → pd.concat()
# 列对齐合并 → pd.merge()
# 索引对齐填充 → df1.combine_first(df2)












# 高效内存连接 → pd.merge() 仍是首选
# 基于指定键（列或索引）将两个 DataFrame 的行关联起来



# inner：仅保留键匹配的行（默认）
# left/right：保留左/右表全部行，缺失值填 NaN
# outer：保留所有行，缺失值填 NaN
# cross：笛卡尔积（所有行组合）



import pandas as pd

df1 = pd.DataFrame({
    'id': [1, 2, 3],
    'name': ['Alice', 'Bob', 'Charlie']
})

df2 = pd.DataFrame({
    'id': [2, 3, 4],
    'salary': [50000, 60000, 70000]
})

# 内连接：仅保留两表共有的 id
result = pd.merge(df1, df2, on='id', how='inner')  # 同名列自动匹配（on 参数可省略）
print(result)




# 左表连接键为 'emp_id'，右表为 'staff_id'
df1 = pd.DataFrame({'emp_id': [1, 2], 'dept': ['HR', 'IT']})
df2 = pd.DataFrame({'staff_id': [2, 3], 'project': ['A', 'B']})

# 左连接：保留所有左表行
result = pd.merge(
    df1, 
    df2, 
    left_on='emp_id',             #  异名列需分别指定（left_on/right_on）
    right_on='staff_id', 
    how='left',
    suffixes=('_left', '_right')  # 表均有 amount 列时，生成 amount_x, amount_y
    , indicator=True  # 添加来源标记列
    , validate='one_to_one' # 提前检查键唯一性，避免意外多对多连接
)
print(result)




# 时间序列补全（merge_ordered）按日期外连接，向前填充缺失值
pd.merge_ordered(stock_prices, economic_indicators, 
                 left_on='date', right_on='release_date', 
                 fill_method='ffill')  # 缺失指标用前值填充



# 最近时间匹配（merge_asof）将订单匹配到最近的时间戳事件
pd.merge_asof(orders, price_changes, left_on='order_time', right_on='change_time', 
              direction='nearest')  # 按最接近的时间匹配





# 避免重复列名冲突
# 提前重命名：df.rename(columns={"old": "new"})
# 使用 suffixes=('_left', '_right') 自动添加后缀




# merge_ordered：有序数据合并利器；专为时间序列等有序数据设计，保留顺序并支持缺失值填充，适合合并不同频率的时间序列（如股票价格与交易量）
# 顺序保留：结果自动按合并键排序（如日期）。
# 填充支持：通过fill_method参数实现前向填充（ffill）或后向填充（bfill）。
# 分组合并：使用left_by/right_by按组分别合并（如按产品类别合并价格）
pd.date_range('2024-01-02', periods=3, freq='2D')  # 2024-01-02  2024-01-04  2024-01-06   

merged = pd.merge_ordered(df_price, df_volume, on='Date', how='outer', fill_method='ffill') # 如果下一列没有匹配上值，用上一列填充

#         Date  Price  Volume
# 0 2024-01-01    100     NaN
# 1 2024-01-02    100  2000.0    <-----------  100 是上一个100 填充的
# 2 2024-01-03    102  2000.0
# 3 2024-01-04    102  2100.0
# 4 2024-01-05    101  2100.0    <-------------- 2100 使用上一个填充的
# 5 2024-01-06    101  1900.0





# merge_asof：最近邻匹配引擎；按最近键值合并（如时间戳），适合金融交易匹配（订单时间→最新行情）、日志对齐等场景
# 最近匹配逻辑：默认direction='backward'（右表键 ≤ 左表键），可选forward或nearest。
    #   backward（默认）：右表键 ≤ 左表键；forward：右表键 ≥ 左表键；nearest：绝对值最近。

# 容差控制：tolerance限制匹配范围（如最大时间差）。允许的最大键值差（如pd.Timedelta(days=1)或数值差）
# 分组匹配：by参数实现分组最近邻匹配（如按产品ID分组）
# allow_exact_matches	是否允许精确匹配（默认True）
merged = pd.merge_asof(
    orders.sort_values('order_time'),  # 左表按订单时间排序
    quotes.sort_values('quote_time'),   # 右表按行情时间排序
    left_on='order_time',              # 左表键：订单时间
    right_on='quote_time',              # 右表键：行情时间
    by='product',                       # 分组键：按产品类别独立匹配
    direction='backward'                # 匹配方向：取不超过订单时间的最近行情
    ,tolerance=pd.Timedelta(minutes=10)  # 最大允许10分钟时间差
)


# 	order_time	product	order_id	quote_time	price
# 0	2024-01-01 09:31:00	A	101	2024-01-01 09:30:00	100
# 1	2024-01-01 09:35:00	B	102	2024-01-01 09:33:00	200
# 2	2024-01-01 09:40:00	A	103	2024-01-01 09:38:00	105   <--------- 如果这条数据没匹配上会，会从上面那个 A 填充到这里，只能从上往下填充（必须是匹配上的）





















# combine_first() 无损填补缺失值，通过优先级规则合并两个数据集
# combine_first()	主从式缺失值填充	自动对齐索引	主数据优先填充
# df2 不会覆盖 df1 的非空值
# 索引不一致：若索引不完全重叠，可能引入额外行（需预先检查索引）

import pandas as pd
import numpy as np

# 主数据集（含缺失）
df1 = pd.DataFrame({
    'A': [1, np.nan, 3], 
    'B': [np.nan, 5, np.nan]
}, index=['X', 'Y', 'Z'])

# 辅助数据集（用于填补）
df2 = pd.DataFrame({
    'A': [np.nan, 2, np.nan],
    'B': [4, np.nan, 6]
}, index=['X', 'Y', 'Z'])

# 填补逻辑：df1的NaN用df2对应位置值替代
result = df1.combine_first(df2)




# 当主辅数据集索引差异大时，结果可能引入意外行  先统一索引再合并
df2_aligned = df2.reindex_like(df1)  # 强制df2使用df1的索引
result = df1.combine_first(df2_aligned)


# 按优先级链式填补：df1 > df2 > df3
result = df1.combine_first(df2).combine_first(df3)


# 性能优化建议
# 大数据集：避免循环调用，优先批量合并。
# 数据类型：填充前用 .astype() 统一类型，减少内存占用

















# -------------------------------------------- 对比总结 ---------------------------------------------------

# 方法	                          适用场景	                    是否覆盖原数据	                        索引处理
# combine_first()	          主数据优先的缺失值填补	              ❌ 不覆盖非空值	                 ✅ 自动对齐并扩展
# fillna()	            单数据集简单填充（常量/插值）	           ✅ 可覆盖	                           ❌ 不扩展索引
# pd.merge()	          基于键的关联查询（类似SQL JOIN）	       ❌ 不覆盖	                         🔄 需显式指定键
# pd.concat()	              轴向堆叠（无填充逻辑）	              ❌ 不覆盖	                      ⚠️ 可保留原索引